package com.kamistoat.meimeichat.meimeichatserverapplication.kcp;

import com.kamistoat.meimeichat.meimeichatserverapplication.netty.NettyServer;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.net.InetSocketAddress;
import java.util.concurrent.Callable;

/**
 * 是无法通过TCP链接服务来获取UDP链接的，因此必须使用额外的一个监听器。
 * Client会向该UDP监听发送请求，服务端才能获取Client的UDP地址
 */
@Service("kcpNettyServer")
public class KcpNettyServer implements Callable<ChannelFuture> {

    private final Logger logger = LoggerFactory.getLogger(NettyServer.class);

    // 当建立P2P时，不存在客户端和服务端的概念。由于UDP链接的特性，因此只需要使用一个Loop
    private final NioEventLoopGroup workGroup = new NioEventLoopGroup();
    // 额外定义的 ChannelFuture 变量，用于记录 Bootstrap.connect() 返回的异步操作句柄，用以检测异步操作是否执行完毕/成功
    private ChannelFuture channelFuture;

    @Value("${netty.ip}")
    private String IP;
    @Value("${netty.UDP_port}")
    private Integer UDP_PORT;

    @Autowired
    KcpNettyServerChannelInitializer kcpNettyServerChannelInitializer;

    @Override
    public ChannelFuture call() throws Exception {
        try {
            // 不存在客户端服务端的概念，因此全部以服务端对待即可。(也有全部以客户端对待的例子)
            Bootstrap bootstrap = new Bootstrap();
            bootstrap
                    .group(workGroup)
                    .channel(NioDatagramChannel.class)
                    .option(ChannelOption.SO_BROADCAST, true)
                    .handler(kcpNettyServerChannelInitializer);
            // 建立UDP监听
            this.channelFuture = bootstrap.bind(new InetSocketAddress(UDP_PORT)).syncUninterruptibly();
        } catch (Exception exception) {
            logger.error("Netty Server P2P Listener Start Error: " + exception.getMessage());
        } finally {
            if (this.channelFuture != null && this.channelFuture.isSuccess()) {
                logger.info("Netty Server P2P Listener Start Success");
            } else {
                destory();
                logger.error("Netty Server P2P Listener Closed");
            }
        }
        return this.channelFuture;
    }

    public boolean isActive() {
        return this.channelFuture.channel().isActive();
    }

    public void destory() {
        this.workGroup.shutdownGracefully();
    }

    public ChannelFuture channelFuture() {
        return this.channelFuture;
    }
}
